package gateway.server.net;

import gateway.api.annotation.GatewayType;
import gateway.api.engine.Connector;
import gateway.api.engine.Engine;
import gateway.server.util.Const;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

/**
 * @author Jin Zheng
 * @since 2020-09-13
 */
public abstract class ServerConnector implements Connector, Runnable
{
	private static Logger logger = LoggerFactory.getLogger(ServerConnector.class);

	public static final String KEY_IO_THREAD = "io-thread";
	public static final String KEY_PORT = "port";

	protected String id;
	protected Engine engine;
	protected Map<String, String> args;

	public ServerConnector()
	{
	}

	@Override
	public void run()
	{
		int ioThread = 2;
		int port = 9000;
		GatewayType type = this.type();
		EventLoopGroup bossGroup = new NioEventLoopGroup(Const.BOSS_GROUP);
		EventLoopGroup workerGroup = new NioEventLoopGroup(ioThread);
		ServerBootstrap bootstrap = new ServerBootstrap();
		try
		{
			bootstrap.group(bossGroup, workerGroup)
					.channel(NioServerSocketChannel.class)
					.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, Const.TIMEOUT)
					.childHandler(this.channelInitializer());

			ChannelFuture channelFuture = bootstrap.bind(port).sync();
			logger.info("{} server started successful，listen port at {}.", type, port);
			channelFuture.channel().closeFuture().sync();
			logger.info("{} server closed.", type);
		}
		catch (Exception e)
		{
			logger.error("Error, ", e);
		}
		finally
		{
			workerGroup.shutdownGracefully();
			bossGroup.shutdownGracefully();
		}
	}

	@Override
	public void initialize() throws Exception
	{
		new Thread(this).start();
	}

	@Override
	public void destroy() throws Exception
	{
	}

	@Override
	public void setArgs(Map<String, String> args)
	{
		this.args = args;
	}

	@Override
	public void setId(String id)
	{
		this.id = id;
	}

	@Override
	public void setEngine(Engine engine)
	{
		this.engine = engine;
	}

	protected abstract ChannelInitializer<SocketChannel> channelInitializer();

	protected abstract GatewayType type();


}
